package cn.seecoder.ai.serviceImpl;

import cn.seecoder.ai.dao.ConfigRepository;
import cn.seecoder.ai.dao.MachineLearningPipelineRepository;
import cn.seecoder.ai.dao.ModelRepository;
import cn.seecoder.ai.enums.LearningTypeEnum;
import cn.seecoder.ai.enums.MachineLearningAlgorithmEnum;
import cn.seecoder.ai.exception.AIExternalException;
import cn.seecoder.ai.model.po.Config;
import cn.seecoder.ai.model.po.MachineLearningPipeline;
import cn.seecoder.ai.model.po.Model;
import cn.seecoder.ai.model.vo.MachineLearningPipelineVO;
import cn.seecoder.ai.model.vo.ModelVO;
import cn.seecoder.ai.service.FileInfoService;
import cn.seecoder.ai.service.MachineLearningPipelineService;
import cn.seecoder.ai.service.ModelService;
import cn.seecoder.ai.utils.POJOConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author DingXiaoyu
 * @date 2023/4/17 14:25
 */
@Service
public class MachineLearningPipelineServiceImpl implements MachineLearningPipelineService {

    @Autowired
    MachineLearningPipelineRepository machineLearningPipelineRepository;

    @Autowired
    FileInfoService fileInfoService;

    @Autowired
    ConfigRepository configRepository;

    @Autowired
    ModelRepository modelRepository;

    @Autowired
    ModelService modelService;

    @Override
    public MachineLearningPipelineVO addPipeline(MachineLearningPipelineVO machineLearningPipelineVO) {
        MachineLearningPipeline machineLearningPipeline=toPO(machineLearningPipelineVO);
        machineLearningPipelineRepository.save(machineLearningPipeline);
        return toVO(machineLearningPipeline);
    }

    @Override
    public List<MachineLearningPipelineVO> findPipelines(Integer userId) {
        List<MachineLearningPipeline> machineLearningPipelines=machineLearningPipelineRepository.findByUserId(userId);
        return machineLearningPipelines.stream().map(this::toVO).collect(Collectors.toList());
    }

    @Override
    public Boolean deletePipeline(Integer pipelineId) {
        machineLearningPipelineRepository.deleteById(pipelineId);
        return true;
    }

    @Override
    public ModelVO usePipeline(Integer pipelineId, Integer fileId, String modelName) {
        MachineLearningPipeline machineLearningPipeline=machineLearningPipelineRepository.findById(pipelineId).get();
        if (!fileInfoService.isFit(machineLearningPipeline.getFeatures(),fileId)){
            throw AIExternalException.columnsNotExist();
        }
        Config config=new Config();
        config.setConfigName(pipelineId+"id生成");
        config.setLearningType(machineLearningPipeline.getMachineLearningAlgorithm()==MachineLearningAlgorithmEnum.K_MEANS_CLUSTERING?
                LearningTypeEnum.UNSUPERVISED_LEARNING:LearningTypeEnum.SUPERVISED_LEARNING);
        config.setFeatures(new ArrayList<>(machineLearningPipeline.getFeatures()));
        config.setLabel(machineLearningPipeline.getLabel());
        config.setUserId(machineLearningPipeline.getUserId());
        config.setCreatedTime(new Date());
        config.setFileInfoId(fileId);
        configRepository.save(config);
        Model model=new Model();
        model.setUserId(machineLearningPipeline.getUserId());
        model.setConfigId(config.getId());
        model.setModelName(modelName);
        model.setMachineLearningAlgorithm(machineLearningPipeline.getMachineLearningAlgorithm());
        model.setTrainParams(machineLearningPipeline.getTrainParams());
        modelRepository.save(model);
        modelService.syncTrainModel(machineLearningPipeline.getUserId(), model.getId());
        return modelService.getModelVO(machineLearningPipeline.getUserId(),model.getId());
    }

    private MachineLearningPipeline toPO(MachineLearningPipelineVO machineLearningPipelineVO){
        return (MachineLearningPipeline) POJOConverter.convert(machineLearningPipelineVO);
    }

    private MachineLearningPipelineVO toVO(MachineLearningPipeline machineLearningPipeline){
        return (MachineLearningPipelineVO) POJOConverter.convert(machineLearningPipeline);
    }
}
